﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading;
using System.Drawing;
using Bds.Inject;
using DienLib.PopUp;

namespace DienLib.SummitLib
{
    public class Command
    {
        /// <summary>
        /// Inject Code from a static "Test Method" into "Summit Main Form". Need : "Class" (in an "Assembly") with "Params" for that Test "Method"
        /// </summary>
        /// <param name="testClass">Test Class in Test Assembly</param>
        /// <param name="staticTestMethod">Test Method in Test Class, must be Static</param>
        /// <param name="testParams">Test Paramter to pass into Test Method</param>
        /// <param name="testAssembly">DLL file that contain test Class & Method</param>
        public static void InjectSummitTest(string testClass, string staticTestMethod = "InjectSummitTest", object[] testParams = null, string testAssembly = "DienLib.dll")
        {
            IntPtr hWnd = StartSummit();
            Injector.InvokeRemote(hWnd, testAssembly, testClass, staticTestMethod, testParams);
        }

        private const string SUMMIT_PATH = "C:\\Program Files\\TIMS\\SBOJ\\OpenJob.UI.exe";
        private const string SUMMIT_PROC = "OpenJob.UI";
        private const string SUMMIT_TITLE = "Summit";
        private static readonly string[] JOB_TITLE = { "Pending", "Active", "Complete", "Cancelled" };
        private const string SERVICE_DELIVERY_PROC = "AKAKAK";
        private const int TIMEOUT_SEC = 30;

        /// <summary>
        /// Start Summit at default Installation PATH : "C:\Program Files\TIMS\SBOJ\OpenJob.UI.exe"
        /// After 60s will Timed-Out Return IntPtr.Zero if Fail to Start
        /// </summary>
        /// <returns>Return Pointer to the OpenJob.UI Process. Return ZERO if Fail to Start</returns>
        public static IntPtr StartSummit()
        {
            try
            {
                Process.Start(SUMMIT_PATH);
                //Thread.Sleep(5000); // Wait for SUMMIT Start
            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.Message, "Cannot START SUMMIT");
                MessageBox.Show("Maybe No SUMMIT install in the following path : " + SUMMIT_PATH + " OR your SUMMIT got problem !");
                return IntPtr.Zero;
            }

            string title = "WAIT FOR SUMMIT START";
            string richtext = "{\\rtf1\\fbidis\\ansi\\ansicpg1258\\deff0\\deflang1066{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset163 Calibri;}{\\f1\\fswiss\\fprq2\\fcharset163 Arial;}{\\f2\\fnil\\fcharset163 Microsoft Sans Serif;}}" +
                "{\\colortbl ;\\red192\\green0\\blue0;\\red0\\green176\\blue240;\\red128\\green128\\blue128;}" +
                "\\viewkind4\\uc1\\pard\\ltrpar\\cf1\\lang1024\\b\\f0\\fs20 SUMMIT take long time to start !\\par" +
                "\\cf2\\b0 Check if \\ldblquote Unsent Job\\rdblquote  Pending ?\\f1\\par" +
                "\\cf3\\f0 A \\ldblquote Yes/No\\rdblquote  Dialog somewhere \\'85\\cf0\\lang1066\\f1\\fs22  \\par" +
                "\\cf2\\lang1024\\f0\\fs20 Or you work with an open JOB ?\\par" +
                "\\pard\\ltrpar\\cf3 Then Save & Close it to continue\\cf0\\lang1066\\f2\\fs17\\par}";

            CountDownForm cdTimer = new CountDownForm(TIMEOUT_SEC, title, richtext, delegate(object sender, out object retform)
            { // STOP COUNT DOWN CHECK METHOD ...
                Process[] procs = Process.GetProcessesByName(SUMMIT_PROC);
                if (procs.Length == 0)
                {
                    // SUMMIT NOT STARTED
                    if ((sender as CountDownForm).IsCounting) { retform = null; return false; }
                    (sender as CountDownForm).Message = "Cannot START SUMMIT ! Maybe No SUMMIT install in the following path : " + SUMMIT_PATH + " OR your SUMMIT got problem !";
                }

                // SUMMIT STARTED
                var list = DienLib.WinAPI.FindWindowLike(procs[0], SUMMIT_TITLE, DienLib.FindCulture.EXACT_MATCH);
                if (list.Count != 0)
                {
                    retform = list[0];
                    return true; // StopCountDown
                }

                retform = null;
                return false;
                // END DELEGATE
            });

            object obj = cdTimer.showdialog();
            return obj == null ? IntPtr.Zero : (IntPtr)obj;
        }

#if false
        /// <summary>
        /// Get the Current (Main Window) Form of Summit that you are working with (Can be the Summit Main Form or the New Job Main Form or other Forms also)
        /// Depend on which Form you are working with ... Note that if you start Service Delivery Trip / Rig Up Down Dialog, OpenJob.UI will run to background
        /// </summary>
        /// <returns>The Summit's Main Window (Form) you are working with. Null if FAIL</returns>
        public static IntPtr GetCurrentHandle()
        {
            Process[] procs = Process.GetProcessesByName(SUMMIT_PROC);
            int i = TIMEOUT_SEC;
            while (procs.Length == 0 & i > 0)
            {
                Thread.Sleep(1000);
                procs = Process.GetProcessesByName(SUMMIT_PROC);
                i--;
            }

            if (procs.Length == 0)
            { // Already Timed-Out
                MessageBox.Show("Please Start SUMMIT first ! No Summit Started, " + TIMEOUT_SEC.ToString() + "s already pass & Timed-out. Try again later !");
                return IntPtr.Zero;
            }

            foreach (Process proc in procs)
            {
                IntPtr pt;
                try
                {
                    pt = proc.MainWindowHandle;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Summit is hidding in background. Maybe Delivery Service Dialog is openned !");
                    continue;
                }
                return pt;
            }

            return IntPtr.Zero;
        }
#endif
        /// <summary>
        /// Get the Main Summit Start UI
        /// </summary>
        /// <returns>Pointer to Main Summit Window</returns>
        public static IntPtr GetSummitMainHandle()
        {
            string title = "WAIT FOR SUMMIT DIALOG";
            string richtext = "{\\rtf1\\fbidis\\ansi\\ansicpg1258\\deff0\\deflang1066{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset163 Calibri;}{\\f1\\fswiss\\fprq2\\fcharset163 Arial;}{\\f2\\fnil\\fcharset163 Microsoft Sans Serif;}}" +
                "{\\colortbl ;\\red192\\green0\\blue0;\\red0\\green176\\blue240;\\red128\\green128\\blue128;}" +
                "\\viewkind4\\uc1\\pard\\ltrpar\\cf1\\lang1024\\b\\f0\\fs20 SUMMIT take long time to start !\\par" +
                "\\cf2\\b0 Check if \\ldblquote Unsent Job\\rdblquote  Pending ?\\f1\\par" +
                "\\cf3\\f0 A \\ldblquote Yes/No\\rdblquote  Dialog somewhere \\'85\\cf0\\lang1066\\f1\\fs22  \\par" +
                "\\cf2\\lang1024\\f0\\fs20 Or you work with an open JOB ?\\par" +
                "\\pard\\ltrpar\\cf3 Then Save & Close it to continue\\cf0\\lang1066\\f2\\fs17\\par}";

            CountDownForm cdTimer = new CountDownForm(TIMEOUT_SEC, title, richtext, delegate(object sender, out object retform)
            { // STOP COUNT DOWN CHECK METHOD ...
                Process[] procs = Process.GetProcessesByName(SUMMIT_PROC);
                if (procs.Length == 0)
                {
                    // SUMMIT NOT STARTED
                    if ((sender as CountDownForm).IsCounting) { retform = null; return false; }
                    (sender as CountDownForm).Message = "Please Start SUMMIT first ! No Summit Started, " + TIMEOUT_SEC.ToString() + "s already pass & Timed-out. Try again later !";
                }

                // SUMMIT STARTED
                //proc.MainWindowTitle == "Summit" : This only TRUE WHEN 1 FORM per Process. What if 2 FORM in 2 Thread same Process.
                //foreach (Process proc in procs) // proc Summit JOB UI luc nao cung chi co 1 process thoi.
                var list = DienLib.WinAPI.FindWindowLike(procs[0], SUMMIT_TITLE, DienLib.FindCulture.EXACT_MATCH);
                if (list.Count != 0)
                {
                    retform = list[0];
                    return true; // StopCountDown
                }

                // SUMMIT STARTED but NO JOB WINDOW
                if (!(sender as CountDownForm).IsCounting) (sender as CountDownForm).Message = "No Summit Main Form, Maybe you are working on job form !"; //Timed Out
                retform = null;
                return false;
                // END DELEGATE
            });

            object obj = cdTimer.showdialog();
            return obj == null ? IntPtr.Zero : (IntPtr)obj;
        }

        /// <summary>
        /// Get the Main Job Form of Summit
        /// </summary>
        /// <returns>Pointer to Main Job Window</returns>
        public static IntPtr GetJobMainHandle()
        {
            string title = "WAIT FOR MAIN JOB DIALOG";
            string richtext = "{\\rtf1\\fbidis\\ansi\\ansicpg1258\\deff0\\deflang1066{\\fonttbl{\\f0\\fswiss\\fprq2\\fcharset163 Calibri;}{\\f1\\fswiss\\fprq2\\fcharset163 Arial;}{\\f2\\fnil\\fcharset163 Microsoft Sans Serif;}}" +
                "{\\colortbl ;\\red192\\green0\\blue0;\\red0\\green176\\blue240;\\red128\\green128\\blue128;}" +
                "\\viewkind4\\uc1\\pard\\ltrpar\\cf1\\lang1024\\b\\f0\\fs20 PRE-JOB PACKAGE NOT FOUND!\\par";

            CountDownForm cdTimer = new CountDownForm(TIMEOUT_SEC, title, richtext, delegate(object sender, out object retform)
                { // STOP COUNT DOWN CHECK METHOD ...
                    Process[] procs = Process.GetProcessesByName(SUMMIT_PROC);
                    if (procs.Length == 0)
                    {
                        // SUMMIT NOT STARTED
                        if ((sender as CountDownForm).IsCounting) { retform = null; return false; }
                        (sender as CountDownForm).Message = "Please Start SUMMIT first ! No Summit Started, " + TIMEOUT_SEC.ToString() + "s already pass & Timed-out. Try again later !";
                    }

                    // SUMMIT STARTED
                    var list = DienLib.WinAPI.FindWindowLike(procs[0], JOB_TITLE, DienLib.FindCulture.PARTIAL_MATCH);
                    if (list.Count != 0)
                    {
                        retform = list[0];
                        return true; // StopCountDown
                    }

                    // SUMMIT STARTED but NO JOB WINDOW
                    if (!(sender as CountDownForm).IsCounting) (sender as CountDownForm).Message = "No Job Main Form, Maybe you are on Summit Main Form or Service Delivery Dialog !"; //Timed Out
                    retform = null;
                    return false;
                    // END DELEGATE
                });

            object obj = cdTimer.showdialog();
            return obj == null ? IntPtr.Zero : (IntPtr)obj;
        }

        public static Form GetSummitMainForm()
        {
            IntPtr hWnd = GetSummitMainHandle();
            if (hWnd == IntPtr.Zero) { MessageBox.Show("There is no Summit Dialog Open or You click Cancel ? If not Please start Summit Dialog or Close Job Dialog first !"); return null; }
            Form _formSummit;
            try { _formSummit = (Form)Control.FromHandle(hWnd); }
            catch (Exception ex) { MessageBox.Show("Cannot get Form Summit from Handle ! Something wrong"); throw ex; }
            if (_formSummit == null) MessageBox.Show("Cannot get Summit Main Form from Handle ! Maybe form Hided or called from different process than Job.UI Process");
            return _formSummit;
        }

        public static Form GetJobMainForm()
        {
            IntPtr hWnd = GetJobMainHandle();
            if (hWnd == IntPtr.Zero) { MessageBox.Show("There is no Job Dialog Open or you Click Cancel ? If not Please open Job from Summit Dialog or Close Service Delivery Dialog first !"); return null; }

            Form _formJob;
            try { _formJob = (Form)Control.FromHandle(hWnd); }
            catch (Exception ex) { MessageBox.Show("Can not get Job Dialog from Handle ! Something wrong !"); throw ex; }

            if (_formJob == null) MessageBox.Show("Cannot get Job Dialog from Handle ! Maybe form Hided because you are open Service Delivery, Close it first !");
            return _formJob;
        }

        public static void DrawBorder(Control Ctrl)
        {
            Ctrl.CreateGraphics().DrawRectangle(new Pen(Color.Crimson, 5), Ctrl.ClientRectangle);
            //ControlPaint.DrawBorder(ctrl.CreateGraphics(), ctrl.ClientRectangle, System.Drawing.Color.Red, ButtonBorderStyle.Solid);
        }

        /// <summary>
        /// Start Blink Border for a normal control by draw on their own graphics
        /// </summary>
        /// <param name="ctrl"></param>
        public static void BlinkBorderBefore(Control Ctrl)
        {
            if (Ctrl == null) throw new ArgumentNullException("Ctrl pass to BlinkBorderBefore is NULL");
            DienLib.SummitLib.Command.DrawBorder(Ctrl);
            System.Threading.Thread.Sleep(WinAPI.GetBlinkSpeed());
        }

        /// <summary>
        /// Stop Blink Border for a normal control by draw on their own graphics & then Refresh to eraser
        /// </summary>
        /// <param name="ctrl"></param>
        public static void BlinkBorderAfter(Control Ctrl)
        {
            if (Ctrl == null) throw new ArgumentNullException("Ctrl pass to BlinkBorderAfter is NULL");
            System.Threading.Thread.Sleep(WinAPI.GetBlinkSpeed());
            DienLib.SummitLib.Command.DrawBorder(Ctrl);
            System.Threading.Thread.Sleep(WinAPI.GetBlinkSpeed());
            if (Ctrl.InvokeRequired) Ctrl.Invoke((MethodInvoker)delegate { Ctrl.Refresh(); }); else Ctrl.Refresh();
        }
    }

}
